package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string
	Age  int
}

func (u User) AgetSun(num, num2 int) int {
	return num + num2
}

func (u User) BPrint() {
	fmt.Println("BPrint方法执行了", u.Name)
}

func main() {
	/*
		num := 10
		testReflect(&num)
		fmt.Println(num)
	*/

	user := User{"张三", 18}
	//testReflect2(&user)

	testReflect3(user)
	fmt.Println(user)
}

func testReflect3(i interface{}) {
	reVal := reflect.ValueOf(i)

	// 通过reflect.Value类型操作结构体内的字段
	zNum := reVal.NumField()
	fmt.Println("属性个数有 ", zNum)
	for i := 0; i < zNum; i++ {
		fmt.Printf("第%d个字段的值是: %v \n", i, reVal.Field(i))
	}

	// 获取内部方法
	fNum := reVal.NumMethod()
	fmt.Println("方法个数有 ", fNum)
	// 调用了BPrint方法
	// 调用方法，方法的首字母必须大写才有对应的反射访问权限
	// 方法的顺序安装ASCII的顺序排序的，abc..对应索引：012
	reVal.Method(1).Call(nil)

	// 调用AgetSun方法
	// 定义一个value的切片
	var args []reflect.Value
	args = append(args, reflect.ValueOf(10))
	args = append(args, reflect.ValueOf(20))
	fmt.Println(args)

	result := reVal.Method(0).Call(args)
	fmt.Println("调用AgetSun方法的结果是：", result[0])

}

// 修改结构体的属性和方法
func testReflect2(i interface{}) {
	reVal := reflect.ValueOf(i)
	// 通过SetInt()方法修改值
	reVal.Elem().FieldByName("Age").SetInt(100)
	reVal.Elem().FieldByName("Name").SetString("李四")
}

// 修改基本数据类型的值
func testReflect(i interface{}) {
	reVal := reflect.ValueOf(i)
	// 通过SetInt()方法修改值
	reVal.Elem().SetInt(100)
}
